package mbp.agents;

import jade.core.Agent;
import jade.core.behaviours.TickerBehaviour;
import jade.lang.acl.ACLMessage;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;
import jade.wrapper.StaleProxyException;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;

import org.apache.log4j.Logger;


import mbp.agents.AMbpBaseAgent.AgentState;
import mbp.base.ContractState;
import mbp.base.MessageType;
import mbp.base.Record;
import mbp.base.Settings;
import mbp.core.Offer;
import mbp.core.Resource;
import mbp.core.ResourceManager;
import mbp.core.ResourceUtility;
import mbp.core.ResourceValidation;
import mbp.exceptions.InvalidValueException;
import mbp.exceptions.ParseExpressionErrorException;
import mbp.message.Copier;
import mbp.message.Message;
import mbp.message.ObjectBuilder;
import mbp.message.contract;
import mbp.message.extra;
import mbp.message.resource;
import mbp.message.utility;

/**
 * Implementuje agenta procesu biznesowego. 
 * @author Wojciech Wilanski
 *
 */
public class MbpClientAgent extends AMbpAgentList
{
	private Logger logger = Logger.getLogger(this.getClass());
	
	// Domyslna nazwa pakietu
	private String packageName = Settings.packageName;
	
	Date dt = new Date();
	Random generator = new Random(dt.getTime());
	
	// Okresla czy powiadamiac agenta managera o kontraktach
	private boolean notifyManager = false;
	
	private boolean businessStarted = false;
	
	private boolean processing = false;
	
	/**
	 * Stan sprawy powierzonej agentowi zadania
	 * @author wojtek
	 *
	 */
	private enum TaskAgentState {
		/**
		 * Czekanie na odpowiedz od agenta zadania
		 */
		WAIT,
		
		/**
		 * Agent zadania nie moze pozyskac zasobu. Nie moze odnalezc zadnych producentow.
		 */
		NOSERVICE,
		
		/**
		 * Agent zadania nie moze pozyskac zasobu. Brak ofert.
		 */
		NOOFFER,
		
		/**
		 * Agent zadania wynegocjowal oferte. Oferta moze sie rowniez pojawic w trakcie tealizacji
		 * kontraktu. Oznacza to ze doszlo do renegocjacji z inicjatywy producenta
		 */
		OFFER,
		
		/**
		 * Agent procesu biznesowego jest gotowy do podpisania kontraktu, zasoby rzeczywiste
		 * i wirualne s� i s� zarezerwowane.
		 */
		READY,
		
		/**
		 * Trwa realizacja kontraktu, faza realizacji
		 */
		REALIZE,
			
		/**
		 * Trwa realizacja kontraktu, faza produkcji zasobu
		 */
		PRODUCE,
		
		/**
		 * Kontrakt zostal wykonany
		 */
		DONE	
	}
	
//	private enum TaskState {
//		PREPARE, READY, REALIZE
//	}
	
	// Lista dzialajacych agentow zadan i ich stan
	private Map<String, Record<TaskAgentState, Object>> taskAgents;
	
	// Lista informacji o kontraktach
	private Map<String, contract> contractList;
	
	@Override
	protected void setup()
	{
		super.setup();
		
		// Pobranie parametrow z jakimi startuje agent:
		// 1 Lista zasobow do pozyskania (ResourceVilidation)
		// 2 Lista posiadanych zasobow (Resource)
		// 3 Lista funkcji uzytecznosci (Resource Utility)
		// 4 Nazwa pakietu np: mbp.agents. Okresla lokalizacje klas agentow: 
		Object[] args = getArguments();
		
		if(args==null)args = new Object[]{};
		
		contractList = new HashMap<String, contract>();
		
		// Tablica dzialajacych agentow zadan
		// | nazwa agenta (key) | stan agenta    | oferta lub kontrakt |
		// |--------------------|----------------|---------------------|
		// | String             | TaskAgentState | Object              |
		taskAgents = Collections.synchronizedMap( new HashMap<String, Record<TaskAgentState,Object>>() );
		
		if(args.length == 3 || args.length == 4)
		{
			// Pobranie argumentow
			List<ResourceValidation> rcvList = (List<ResourceValidation>) args[0];
			List<Resource> rcList = (List<Resource>) args[1];
			List<ResourceUtility> rcuList = (List<ResourceUtility>) args[2];
			
			for(int i = 0; i<rcvList.size(); i++)
			{
				// Lista funkcji walidacji. Pelni role listy zasobow do pozyskania przez agenta
				// Record:  | funkcja walidacji  | Nazwa agenta zadania     | Nazwa agenta dla ktorego |
				//          |                    | powolanego do pozyskania | jest pozyskiwany         |
				//          |--------------------|--------------------------|--------------------------|
				//          | ResourceValidation | String                   | String                   |
				validationList.add(new Record<ResourceValidation, Object[]>(rcvList.get(i), new Object[]{"", ""}));
			}
			for(int i = 0; i<rcList.size(); i++)
			{
				// Wstawienie zasobu na liste. Record jest obiektem przechowujacym zasob i dodatkowe informacje
				// Record:  | Zasob    | Rezerwacja | Dostepnosc | Agent pozyskujacy |
				//       :  |----------|------------|------------|-------------------|
				//       :  | Resource | String     | Long       | String            |
				resourceList.add(new Record<Resource, Object[]>(rcList.get(i), new Object[]{"", new Long(0), ""}));
			}
			
			for(int i = 0; i<rcuList.size(); i++)
			{
				// Lista funkcji uzytecznosci
				utilityList.add(new Record<ResourceUtility, Object[]>(rcuList.get(i), new Object[]{""}));
			}
			
			logger.info("Agent " + getAID().getName() + " is ready.");
		}
		else
		//{
		//	logger.error("Agent " + getAID().getName() + " error parameters count. Deleting agent...");
		//	this.doDelete();
		//}
		
		// Pobranie 4 argumentu. Nazwa pakietu agentow: Agent Zadania, Agent Podstawowy
		if(args.length == 4)
		{
			packageName = (String) args[3];
		}
		
		// Uruchomienie workera, ktorego zadaniem jest cykliczne nadzorowanie procesu biznesowego
		ClientAgentTicker clientWorker = new ClientAgentTicker(this, 5000);
		addBehaviour(clientWorker);
		
		//printRcInfo();
	}
	
	
	@Override
	protected void processMessage(Message iMsg, String senderName) {
		MessageType messageType = iMsg.getMessageType();
		switch(messageType)
		{
		case RESOURCEL:
			onResourceL(iMsg, senderName);
			break;
		// Brak ofert lub brak uslugi
		case NOSERVICE:
			onNoService(iMsg, senderName);
			break;
		case REJECT:
			onReject(iMsg, senderName);
			break;
		case OFFER:
			onOffer(iMsg, senderName);
			break;
		case NOOFFER:
			onNoOffer(iMsg, senderName);
			break;
		case ACCEPTCONTRACT:
			onAcceptContract(iMsg, senderName);
			break;
		case CONTRACT:
			onContract(iMsg, senderName);
			break;
		case DONE:
			onDone(iMsg, senderName);
			break;
		case EXTRA:
			onExtra(iMsg, senderName);
			break;
		default:
			//logger.warn("Message type: " + messageType + " not supported");
			break;			
		}	
	}
	
	/**
	 * Nadpisanie metody za wzgledu na sposob przechowywania listy
	 */
	@Override
	protected void onValidation(mbp.message.Message iMsg, String senderName)
	{
		ResourceValidation rv = iMsg.getResourceValidation().get(0);
		validationList.add(new Record<ResourceValidation, Object[]>(rv, new Object[]{"", ""}));
	}
	
	/**
	 * Nadpisanie metody. Implementuje dodatkowa funkcjonalnosc
	 */
	@Override
	protected void onResourceLGet(mbp.message.Message iMsg, String senderName)
	{
		// Jezeli brak obiektu extra metoda dziala normalnie
		if(iMsg.getContentXml().extras.size() == 0)
		{
			super.onResourceLGet(iMsg, senderName);
		}
		// W przypadku obiektu extra zwracana jest lista zawierajaca typy zawarte w obiekcie extra
		// i tylko te ktore nie sa zarezrwowane i sa dostepne w magazynie
		else
		{
			List<extra> typeInfoList = iMsg.getContentXml().extras;
			List<resource> rcToSend = new ArrayList<resource>();
			ObjectBuilder objectBuilder = new ObjectBuilder();
			for(int i = 0; i<typeInfoList.size(); i++)
			{
				extra typeInfo = iMsg.getContentXml().extras.get(i);
				if(typeInfo.name.compareTo("type")!=0)
					continue;
				
				for(int j = 0; j<resourceList.size(); j++)
				{
					Resource rc = resourceList.get(j).value0;
					if(rc.getType().getResourceTypeName().compareTo(typeInfo.value)==0)
					{
						String rez = (String) resourceList.get(j).value1[0];
						Long av = (Long) resourceList.get(j).value1[1];
						if(rez.compareTo("")==0 && av==0)
						{
							rcToSend.add(objectBuilder.getResourceInfo(rc));
						}
					}
				}
			}
			
			Message message = new Message(MessageType.RESOURCEL, getLocalName(), senderName);
			message.getContentXml().resources = rcToSend;
			ACLMessage msgReply = message.GetACLMessage();
			SenderLogger.send(this, msgReply);	
			
		}		
	}
	
	/**
	 * Nadpisanie metody za wzgledu na sposob przechowywania listy
	 */
	@Override
	protected void onResource(mbp.message.Message iMsg, String senderName)
	{
		Resource resourceTmp = iMsg.getResource();
		//resourceTmp.setOwner(getLocalName());
		addResource(resourceTmp);
//		List<Resource> listTmp = new ArrayList<Resource>();
//		
//		// Wyznaczenie zasobow z ktorymi potencjalne mozna scalic odebrany zasob
//		for(int i = 0; i<resourceList.size(); i++)
//		{
//			String rez = (String) resourceList.get(i).value1[0];
//			long av = (Long) resourceList.get(i).value1[1];
//			if(rez.compareTo("")==0 && av==0)
//			{
//				listTmp.add(resourceList.get(i).value0);
//			}			
//		}
//		
//		if(ResourceManager.tryToMerge(listTmp, resourceTmp))
//		{
//			resourceTmp = null;
//		}
//		else
//		{
//			resourceList.add(new Record<Resource, Object[]>(resourceTmp, new Object[]{"", new Long(0), ""}));
//		}
	}
	
	
	/**
	 * Nadpisanie metody. Implementuje dodatkowa funkcjonalnosc
	 */
	@Override
	protected void onUtilityLGet(mbp.message.Message iMsg, String senderName)
	{
		// Jezeli brak obiektu extra metoda dziala normalnie
		if(iMsg.getContentXml().extras.size() == 0)
		{
			super.onUtilityLGet(iMsg, senderName);
		}
		else
		{
			List<extra> typeInfoList = iMsg.getContentXml().extras;
			List<utility> rcuToSend = new ArrayList<utility>();
			ObjectBuilder objectBuilder = new ObjectBuilder();
			
			for(int i = 0; i<typeInfoList.size(); i++)
			{
				extra typeInfo = iMsg.getContentXml().extras.get(i);
				if(typeInfo.name.compareTo("type")!=0)
					continue;
				
				for(int j = 0; j<utilityList.size(); j++)
				{
					String rcuType = utilityList.get(j).value0.getType().getResourceTypeName();
					if(rcuType.compareTo(typeInfo.value)==0)
					{
						rcuToSend.add(objectBuilder.getUtilityInfo(utilityList.get(j).value0));
						continue;
					}
				}
			}
			
			Message message = new Message(MessageType.UTILITYL, getLocalName(), senderName);
			message.getContentXml().utilities = rcuToSend;
			ACLMessage msgReply = message.GetACLMessage();
			SenderLogger.send(this, msgReply);		
		}
	}
	
	/**
	 * Odebranie listy zasobow
	 * @param iMsg
	 * @param senderName
	 */
	private void onResourceL(mbp.message.Message iMsg, String senderName)
	{
		ObjectBuilder obb = new ObjectBuilder();
		for(int i = 0; i<iMsg.getContentXml().resources.size(); i++)
		{
			Resource resourceTmp = obb.getResource(iMsg.getContentXml().resources.get(i));
			addResource(resourceTmp);
			
//			List<Resource> listTmp = new ArrayList<Resource>();
//			
//			
//			// Wyznaczenie zasobow z ktorymi potencjalne mozna scalic odebrany zasob
//			for(int j = 0; j<resourceList.size(); j++)
//			{
//				String rez = (String) resourceList.get(j).value1[0];
//				long av = (Long) resourceList.get(j).value1[1];
//				if(rez.compareTo("")==0 && av==0)
//				{
//					listTmp.add(resourceList.get(j).value0);
//				}			
//			}
//			
//			if(ResourceManager.tryToMerge(listTmp, resourceTmp))
//			{
//				resourceTmp = null;
//			}
//			else
//			{
//				resourceList.add(new Record<Resource, Object[]>(resourceTmp, new Object[]{"", new Long(0), ""}));
//			}
			
			
			//resourceList.add(new Record<Resource, Object[]>(resourceTmp, new Object[]{"", new Long(0), ""}));		
		}	
	}
	
	/**
	 * Odebranie wiadomosci NOSERVICE od agenta zadania: Brak uslugi
	 * @param iMsg
	 * @param senderName
	 */
	private void onNoService(mbp.message.Message iMsg, String senderName)
	{
		logger.warn("Recieved NOSERVICE from: " + senderName);
		if(taskAgents.containsKey(senderName))
		{
			taskAgents.put(senderName, new Record<TaskAgentState, Object>(TaskAgentState.NOSERVICE, null));
		}
	}
	
	/**
	 * Odebranie wiadomosci NOSERVICE od agenta zadania: Brak ofert
	 * @param iMsg
	 * @param senderName
	 */
	private void onNoOffer(mbp.message.Message iMsg, String senderName)
	{
		logger.warn("Recieved NOOFFER from: " + senderName);
		if(taskAgents.containsKey(senderName))
		{
			taskAgents.put(senderName, new Record<TaskAgentState, Object>(TaskAgentState.NOOFFER, null));
		}
	}
	
	/**
	 * Wyslanie prosby o czasowe wstrzymanie wykonywania sie aktywnych kontraktow
	 */
	private void freezeContracts()
	{
		Iterator<String> it = taskAgents.keySet().iterator();
		while(it.hasNext())
		{
			String agent = it.next();
			Record<TaskAgentState, Object> rcd = taskAgents.get(agent);
			if(rcd.value0 == TaskAgentState.REALIZE || rcd.value0 == TaskAgentState.PRODUCE)
			{
				contract cntr = (contract) rcd.value1;
				String cUuid = cntr.uuid;
				
				Message message = new Message(MessageType.FREEZE, getLocalName(), agent);
				extra ex = new extra();
				ex.name = "uuid";
				ex.value = cUuid;
				message.getContentXml().extras.add(ex);
				
				ACLMessage msg = message.GetACLMessage();
				SenderLogger.send(this, msg);
			}
		}
	}
	
	/**
	 * Wyslanie prosby o wznowienie wykonywania sie aktywnych kontraktow
	 */
	private void resumeContracts()
	{
		Iterator<String> it = taskAgents.keySet().iterator();
		while(it.hasNext())
		{
			String agent = it.next();
			Record<TaskAgentState, Object> rcd = taskAgents.get(agent);
			if(rcd.value0 == TaskAgentState.REALIZE || rcd.value0 == TaskAgentState.PRODUCE)
			{
				contract cntr = (contract) rcd.value1;
				String cUuid = cntr.uuid;
				if(contractList.containsKey(cUuid))
				{
					if(contractList.get(cUuid).state.compareTo("FROZEN")==0)
					{
						Message message = new Message(MessageType.RESUME, getLocalName(), agent);
						extra ex = new extra();
						ex.name = "uuid";
						ex.value = cUuid;
						message.getContentXml().extras.add(ex);
						
						ACLMessage msg = message.GetACLMessage();
						SenderLogger.send(this, msg);
					}
				}
				//if(cntr.state.compareTo("FROZEN")==0)
				//{
				
//				Message message = new Message(MessageType.RESUME, getLocalName(), agent);
//				extra ex = new extra();
//				ex.name = "uuid";
//				ex.value = cUuid;
//				message.getContentXml().extras.add(ex);
//				
//				ACLMessage msg = message.GetACLMessage();
//				SenderLogger.send(this, msg);
				//}
			}
		}
	}
	
	/**
	 * Odebranie wiadomosci REJECT
	 * @param iMsg
	 * @param senderName
	 */
	private void onReject(mbp.message.Message iMsg, String senderName)
	{		
		// Ustalenie czy komunikat przyszedl od wlasciwego agenta zadania
		if(taskAgents.containsKey(senderName))
		{
			Record<TaskAgentState, Object> rcd = taskAgents.remove(senderName);
			
			// Kontrakt w trakcie realizacji, zerwanie dotyczy realizowanego kontraktu
			if(rcd.value0 ==  TaskAgentState.REALIZE)
			{
				Long pozDt = new Long(0);
				
				// Uaktualnienue stanu kontraktu, zmiana na REJECT
				String uuid = iMsg.getContentXml().extras.get(0).value;
				contractList.get(uuid).state = "REJECTED";
				
				// Powiadomienie managera
				if(notifyManager) {
					sendContractList();
				}
				
				// Przetworzenie zasobow posiadanych przez agenta i usuniecie tych ktore nie zostana zrealizowane
				int index = 0;
				while(index < resourceList.size())
				{
					Record<Resource, Object[]> rcdRc = resourceList.get(index);
					String rez = (String) rcdRc.value1[0];
					String poz = (String) rcdRc.value1[2];
					
					// Zwolnienie rezerwacji, jesli jakies istnieja
					if(rez.compareTo(senderName)==0)
					{
						resourceList.get(index).value1[0] = "";
					}
					
					// Usuniecie zasobu wirtualnego, ktory mial byc wynikiem realizacji zerwanego kontraktu
					if(poz.compareTo(senderName)==0)
					{
						// Pobranie daty realizacji zasobu
						pozDt = new Long( (Long) resourceList.get(index).value1[1] );
						resourceList.remove(index);
						index = 0;
					}
					index = index + 1;
				}
				
				// Wycofanie z magazynu zasobow ktore byly do dyspozycji agenta
				Message message = new Message(MessageType.RESOURCELGET, getLocalName(), Settings.storageName);
				extra ex = new extra();
				ex.name = "owner";
				ex.value = senderName;
				message.getContentXml().extras.add(ex);
				ACLMessage msg = message.GetACLMessage();	
				SenderLogger.send(this, msg);
				
				// Usuniece z listy RCV - zasobow do pozyskania nazwy agenta i obliczenie nowej ilosci
				// jednostek czasu ze wzgledu na trwajaca realizacje procesu biznesowego
				for(int i = 0; i<validationList.size(); i++)
				{
					Record<ResourceValidation, Object[]> rcdRcv = validationList.get(i);
					
					// Zasob ktory mial byc wynikiem zrealizowanego kontraktu
					String agentPoz = (String) rcdRcv.value1[0];
					if(agentPoz.compareTo(senderName)==0)
					{
						validationList.get(i).value1[0] = "";
						
						// Obliczenie nowych jednostek czasu
						Calendar calendar = Calendar.getInstance();
						Long msec = pozDt - calendar.getTimeInMillis();
						Integer newTerm = (int) (msec / 1000);
						validationList.get(i).value0.integerValue = newTerm;
					}
				}
				
				sendDoDelete(senderName);
				
				freezeContracts();
			}//if(rcd.value0 ==  TaskAgentState.REALIZE)
			
			// Oczekiwanie na odpowiedz od agenta zadania
			if(rcd.value0 ==  TaskAgentState.WAIT)
			{
				String uuid = iMsg.getContentXml().extras.get(0).value;
				contractList.get(uuid).state = "REJECTED";

				
				// Powiadomienie managera
				if(notifyManager) {
					sendContractList();
				}
				
				sendDoDelete(senderName);
			}
		}//if(taskAgents.containsKey(senderName))
		
		// Pobranie zwroconych przez serwer zasobow, jezeli serwer cos zwrocil
		ObjectBuilder obb = new ObjectBuilder();
		for(int i = 0; i<iMsg.getContentXml().resources.size(); i++)
		{
			Resource rc = obb.getResource(iMsg.getContentXml().resources.get(i));
			addResource(rc);
			//rc.setOwner(new String(getLocalName()));
			//resourceList.add(new Record<Resource, Object[]>(rc, new Object[]{"", new Long(0), ""}));
			
		}
		
	}
	
	/**
	 * Pozytywne zakonczenia kontraktu
	 * @param iMsg
	 * @param senderName
	 */
	private void onDone(mbp.message.Message iMsg, String senderName)
	{
		if(taskAgents.containsKey(senderName))
		{
			ObjectBuilder obb = new ObjectBuilder();
			
			// Modyfikacja stanu agenta
			taskAgents.get(senderName).value0 = TaskAgentState.DONE;
			
			// Zapisanie danych kontraktu
			taskAgents.get(senderName).value1 = iMsg.getContentXml().contracts.get(0);
			
			// Lista wyprodukowanych zasobow, przeslanych przez serwer
			List<resource> rciProduced = iMsg.getContentXml().resources;
			
			// Lista identyfikatorow zasobow przeznaczonych do wyslania do magazynu
			List<String> toStorage = new ArrayList<String>();
			
			// Przejscie przez liste zasobow agenta zadania i sprawdzenie nazwy agenta pozyskujacego
			for(int i = 0; i<resourceList.size(); i++)
			{
				Record<Resource, Object[]> rcdRc = resourceList.get(i);
				String rez = (String) rcdRc.value1[0];
				String poz = (String) rcdRc.value1[2];
				if(poz.compareTo(senderName)==0)
				{
					
					// Prejscie przez liste zasobow otrzymanych od serwera
					for(int j = 0; j<rciProduced.size(); j++)
					{
						if(rciProduced.get(j).type.compareTo(rcdRc.value0.getType().getResourceTypeName())==0)
						{
							// Zmiana zasobu i parametrow opisujacych zasob
							rcdRc.value0 = obb.getResource(rciProduced.get(j));
							rcdRc.value0.setOwner(getLocalName());
							rcdRc.value1[1] = new Long(0);
							rcdRc.value1[2] = "";
							
							// Jesli byl dla kogos zarezerwowany zostanie przeslany do magazynu
							if(rez.compareTo("")!=0)
							{
								toStorage.add(rcdRc.value0.getUUID());
							}
						}
					}
				}
			}
			
			// Jezeli zasob jest zarezerwowany wysylany jest do dyzpozycji tego serwera
			Iterator<String> it1 = toStorage.iterator();
			while(it1.hasNext())
			{
				String uuidToStorage = it1.next();
				
				Iterator<Record<Resource, Object[]>> it2 = resourceList.iterator();
				while(it2.hasNext())
				{
					Record<Resource, Object[]> rcdRcToStorage = it2.next();
					String uuid = rcdRcToStorage.value0.getUUID();
					if(uuidToStorage.compareTo(uuid)==0)
					{
						Resource rc = rcdRcToStorage.value0;
						// zmiana wlasciciela
						String rez = (String) rcdRcToStorage.value1[0];
						rc.setOwner(new String(rez));
						
						// Wyslanie zasobu do magazynu
						sendResource(rc, Settings.storageName);
						
						// Usuniecie zasobu z listy agenta zadania
						it2.remove();
					}					
				}
			}
			
			contract cntrToSave = Copier.cloneContractInfo(iMsg.getContentXml().contracts.get(0));
			contractList.put(cntrToSave.uuid, cntrToSave);
			
			if(notifyManager) {
				sendContractList();
			}
		}
	}
	
	/**
	 * Odebranie wynegocjowanej oferty od agenta zadania. Oferta pojawia sie gdy
	 * agenta zadanie nie moze sam podpisac kontraktu (brak zasobow)
	 * @param iMsg
	 * @param senderName
	 */
	private void onOffer(mbp.message.Message iMsg, String senderName)
	{
		Offer offer = iMsg.getOffer();
		if(taskAgents.containsKey(senderName))
		{
			taskAgents.put(senderName, new Record<TaskAgentState, Object>(TaskAgentState.OFFER, offer));
			logger.info("Recieved offer from Task Agent: " + senderName);
		}
	}
	
	private void onAcceptContract(mbp.message.Message iMsg, String senderName)
	{
		if(taskAgents.containsKey(senderName))
		{
			logger.info("Recieved ACCEPTCONTRACT from Task Agent: " + senderName);
			contract cntr = iMsg.getContentXml().contracts.get(0);
			taskAgents.put(senderName, new Record<TaskAgentState, Object>(TaskAgentState.REALIZE, cntr));
			
			// Wstawienie posiadanych zasobow (ktore nie sa wirtualne) do magazynu do dyspozycji serwera
			Iterator<Record<Resource, Object[]>> it = resourceList.iterator();
			while(it.hasNext())
			{
				Record<Resource, Object[]> rcdRc = it.next();
				String rez = (String) rcdRc.value1[0];
				//String poz = (String) rcdRc.value1[2];
				Long term = (Long) rcdRc.value1[1];
				if(rez.compareTo(senderName)==0 && term == 0)
				{
					//Record<Resource, Object[]> rcdRcToStorage = resourceList.remove(index);
					Resource rc = rcdRc.value0;
					rc.setOwner(new String(senderName));
					sendResource(rc, Settings.storageName);
					it.remove();
				}	
			}
			
			// Zamiana jednostek czasu na date wyprodukowania zaosbu
			Iterator<Record<Resource, Object[]>> it2 = resourceList.iterator();
			while(it2.hasNext())
			{
				Record<Resource, Object[]> rcdRc = it2.next();
				String poz = (String) rcdRc.value1[2];
				if(poz.compareTo(senderName)==0)
				{
					// Zamiana jednostek czasu na date w formacie Long, kiedy zasob ma sie pojawic
					Long term = (Long) rcdRc.value1[1];
					Calendar calendar = Calendar.getInstance();
					calendar.add(Calendar.SECOND, (int) (term * Settings.getMultiplier()));
					rcdRc.value1[1] = calendar.getTime().getTime();
				}
				
			}
			
			
			// Wstawienie kopii kontraktu do archiwum kontraktow
			contract cntrToSave = Copier.cloneContractInfo(cntr);
			contractList.put(cntrToSave.uuid, cntrToSave);
			
			// Powiadomienie managera
			if(notifyManager) {
				sendContractList();
			}
		}
	}
	
	/**
	 * Odebranie informacji o kontrakcie TYMCZASOWA IMPLEMANTACJA
	 * @param iMsg
	 * @param senderName
	 */
	private void onContract(mbp.message.Message iMsg, String senderName)
	{
		if(taskAgents.containsKey(senderName))
		{
			contract cntr = iMsg.getContentXml().contracts.get(0);
			ContractState contractState = ContractState.valueOf( cntr.state );
			switch(contractState)
			{
			case BROKEN:
				break;
			case CLOSED:
				break;
			case NEW:
				break;
			case PRODUCE:
				taskAgents.put(senderName, new Record<TaskAgentState, Object>(TaskAgentState.PRODUCE, cntr));
				break;
			case REALIZE:
				break;
			case REJECTED:
				break;
			}
		
			contract cntrToSave = Copier.cloneContractInfo(cntr);
			contractList.put(cntrToSave.uuid, cntrToSave);
			
			if(notifyManager) {
				sendContractList();
			}
		}
	}
	
	private void onExtra(mbp.message.Message iMsg, String senderName)
	{
		extra ex = iMsg.getContentXml().extras.get(0);
		if(ex.name.compareTo("notify")==0)
		{
			if(ex.value.compareTo("1")==0)
			{
				notifyManager = true;
				sendContractList();
			}
			if(ex.value.compareTo("0")==0)
			{
				notifyManager = false;
			}
		}
	}
	
	private void sendResource(Resource resource, String agentName)
	{
		mbp.message.Message iMsg = new mbp.message.Message(MessageType.RESOURCE, this.getLocalName(), agentName);
		iMsg.setResource(resource);
		SenderLogger.send(this, iMsg.GetACLMessage());
	}
	
	/**
	 * Dodaje prawdziwy zasob do wewnetrznej pamieci zsobow. Metoda dodatkowo laczy zasoby
	 * jezeli jest taka mozliwosc
	 * @param resource
	 */
	private void addResource(Resource resource)
	{
		resource.setOwner(getLocalName());
		List<Resource> listTmp = new ArrayList<Resource>();
		// Wyznaczenie zasobow z ktorymi potencjalne mozna scalic odebrany zasob
		for(int i = 0; i<resourceList.size(); i++)
		{
			String rez = (String) resourceList.get(i).value1[0];
			long av = (Long) resourceList.get(i).value1[1];
			if(rez.compareTo("")==0 && av==0)
			{
				listTmp.add(resourceList.get(i).value0);
			}			
		}
		
		if(ResourceManager.tryToMerge(listTmp, resource))
		{
			resource = null;
		}
		else
		{
			resourceList.add(new Record<Resource, Object[]>(resource, new Object[]{"", new Long(0), ""}));
		}
	}
	
	
	/**
	 * Uruchamia Agenta Zadania.
	 * @param agentClass
	 * 	Klasa agenta zadania
	 * @param agentName
	 *  Nazwa agenta zadania
	 * @param params
	 *  Argumenty startowe
	 * @return
	 */
	private boolean startAgent(String agentClass, String agentName, Object[] params)
	{
		boolean result;
		AgentContainer ac = getContainerController();
		try 
		{
			AgentController agntToStart = ac.createNewAgent(agentName, agentClass, params);
			agntToStart.start();
			result = true;
		}
		catch (StaleProxyException ex1) 
		{
			logger.error("StaleProxyException", ex1);
			result = false;
		}
		catch (Exception ex2)
		{
			logger.error("Exception", ex2);
			result = false;
		}
		
		return result;
	}
	
	private void sendAcceptOffer(String taskAgentName, String uuid, List<Resource> rcAdvance)
	{
		Message iMsg = new Message(MessageType.ACCEPTOFFER, this.getLocalName(), taskAgentName);
		
		// Identyfikator oferty
		extra ex = new extra();
		ex.name = "uuid";
		ex.value = uuid;
		
		// Zasoby zaliczka - wyslanie do magazynu
		for(int i =0; i<rcAdvance.size(); i++)
		{
			sendResource(rcAdvance.get(i), Settings.storageName);
		}
		
		iMsg.getContentXml().extras.add(ex);
		SenderLogger.send(this, iMsg.GetACLMessage());
	}
	
	private void sendDoDelete(String taskAgentName)
	{
		Message message = new Message(MessageType.DODELETE, getLocalName(), taskAgentName);
		ACLMessage msgReply = message.GetACLMessage();
		SenderLogger.send(this, msgReply);
	}
	
//	/**
//	 * Wyslanie 
//	 * @param index
//	 */
//	private void sendReject(int index)
//	{
//		Message iMsg = new Message(MessageType.REJECT, this.getLocalName(), taskAgentName);		
//		extra ex = new extra();
//		ex.name = "uuid";
//		ex.value = uuid;
//		iMsg.getContentXml().extras.add(ex);
//		SenderLogger.send(this, iMsg.GetACLMessage());
//	}
	
	/**
	 * Wyalanie listy kontraktow do mamagera w celu uaktualnienia listy na gui
	 */
	private void sendContractList()
	{
		Iterator<String> it = contractList.keySet().iterator();
		List<contract> cntriList = new ArrayList<contract>();
		while(it.hasNext())
		{
			String key = it.next();
			cntriList.add(contractList.get(key));
		}
		extra ext = new extra();
		ext.name = "contract";
		ext.value = "";
		mbp.message.Message iMsgToMgr = new mbp.message.Message(MessageType.EXTRA, this.getLocalName(), Settings.managerName);
		iMsgToMgr.getContentXml().extras.add(ext);
		iMsgToMgr.getContentXml().contracts = cntriList;
		SenderLogger.send(this, iMsgToMgr.GetACLMessage());
	}
	
	/**
	 * Sprawdza liste dostepnych zasobow w odniesieniu do pobranej oferty.
	 * Pasujace zasoby sa rezerwowane, a dla brakujacych toworzona jest lista.
	 * @param offer
	 *  Oferta do sprawdzenia
	 * @param taskAgentName
	 *  Nazwa agenta zadania
	 * @return
	 */
	private List<ResourceValidation> checkResources(Offer offer, String taskAgentName)
	{
		// Lista na brakujace zasoby
		List<ResourceValidation> missingRc = new ArrayList<ResourceValidation>();
		
		// Lista wszystkich zasobow wejsciowych uslugi
		List<ResourceValidation> rcvForOffer = offer.getResourcesIn(-1);
		
		
		boolean isOnList;
		
		// Przjscie przez wszystkie zasoby wejsciowe uslugi
		for(int i = 0; i<rcvForOffer.size(); i++)
		{
			isOnList = false;
			ResourceValidation rcvFO = rcvForOffer.get(i);
			
			// Przypadek gdy w ofercie nie jest wymagany zasob danego typu. ilosc=0
			int quantity = rcvFO.getQuantity();
			if(quantity==0)
			{
				continue;
			}
			
			String rcvType = rcvFO.getType().getResourceTypeName();
			
			// Przejscie przez wszystkie dostepne zasoby
			for(int j = 0; j<resourceList.size(); j++)
			{
				Record<Resource, Object[]> rec = resourceList.get(j);
				Resource rc = rec.value0;
				String rcType = rc.getType().getResourceTypeName();
				
				// Inny typ zasobu
				if(rcType.compareTo(rcvType) != 0)
					continue;
				
				// Typ zasobu zgodny, sprawdzenie czy zasob nie jest juz zarezerwowany
				String rez = (String) rec.value1[0];
				long term = (Long) rec.value1[1];
				if(rez.compareTo("")==0)
				{
					try {
						// Walidacja zasobu, rzeczywistego, jesli dobra w zasobie jest wiecej zasob jest dzielony
						if(term==0)
						{
							if(rcvFO.validateCondition(rc))
							{
								int needed = rcvFO.getQuantity();
								int available = resourceList.get(j).value0.getQuantity();
								if(needed==available)
								{
									resourceList.get(j).value1[0] = new String(taskAgentName);
								}
								else
								{
									Resource rcToRez = ResourceManager.divideResource(resourceList.get(j).value0, needed);
									resourceList.add(new Record<Resource, Object[]>(rcToRez, new Object[]{new String(taskAgentName), new Long(0), ""}));
								}
								isOnList = true;
								break;
							}
						}
						// Walidacja zasobu virtualnego zasob nie moze byc dzielony
						else
						{
							rcvFO.setExactQt(true);
							if(rcvFO.validateCondition(rc))
							{
								resourceList.get(j).value1[0] = new String(taskAgentName);
								isOnList = true;
								rcvFO.setExactQt(false);
								break;
							}
						}
						
//						if(rcvFO.validateCondition(rc))
//						{
//							// Sprawdzenie czy trzeba zasob podzielic
//							int needed = rcvFO.getQuantity();
//							int available = resourceList.get(j).value0.getQuantity();
//							if(needed==available)
//							{
//								// Rezerwacja zasobu
//								resourceList.get(j).value1[0] = new String(taskAgentName);
//							}
//							else
//							{
//								
//								Resource rcToRez = ResourceManager.divideResource(resourceList.get(j).value0, needed);
//								resourceList.add(new Record<Resource, Object[]>(rcToRez, new Object[]{new String(taskAgentName), new Long(0), ""}));
//								
//							}
//							// Jesli spelna warunki oferty zasob jest rezerwowany
//							// resourceList.get(j).value1[0] = new String(taskAgentName);
//							isOnList = true;
//							break;
//						}
					} catch (ParseExpressionErrorException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (InvalidValueException e) {
						
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}//for(int j = 0; j<resourceList.size(); j++)
			
			// Jesli zasobu nie odnaleziono na liscie zasobow dostepnych, kopia obiektu ResourceValidation
			// z listy zasobow wejsciowych dodawana jest do listy brakujacych
			if(!isOnList)
			{
				missingRc.add( Copier.cloneResourceValidation(rcvForOffer.get(i)) );
			}
		}//for(int i = 0; i<rcvForOffer.size(); i++)		
		return missingRc;
	}
	
	/**
	 * Metoda przeznaczona do sprawdzenia czy brakujace zasoby sa juz na liscie zasobow do pozyskania
	 * przez agenta. Na podstawie listy brakujacych zasobow, stworzonej przez metode checkResources(...)
	 * tworzona jest nowa lista ktora nie zawiera zasobow ktore sa juz w trakcie pozyskiwania. 
	 * @param missingRc
	 * @return
	 */
	private List<ResourceValidation> checkValidations(List<ResourceValidation> missingRc, String agentName)
	{
		// Nowa lista brakujacch zasobow
		List<ResourceValidation> newRcToGain = new ArrayList<ResourceValidation>();
		boolean isOnList;
		
		// Przejscie przez pierwotna liste brakujacych zasobow
		for(int i = 0; i<missingRc.size(); i++)
		{
			isOnList = false;
			ResourceValidation missRcv = missingRc.get(i);
			String missRcvType = missRcv.getType().getResourceTypeName();
			
			// Przejscie przez liste zasobow do pozyskania przez agenta
			for(int j = 0; j<validationList.size(); j++)
			{
				ResourceValidation rcvToGain = validationList.get(j).value0;
				String toAgent = (String) validationList.get(j).value1[1];
				// Sprawdzenie typu
				if(rcvToGain.getType().getResourceTypeName().compareTo(missRcvType)==0)
				{
					// Sprawdzenie warunku
					if(rcvToGain.getCondition().compareTo(missRcv.getCondition())==0)
					{
						// Sprawdzenie czy to zasob dla tego agenta
						if(toAgent.compareTo(agentName)==0)
						{
							// Jesli typ i warunek sa zgodne oznacza to ze ten zasob jest juz w trakcie pozyskiwanaia
							isOnList = true;
						}
						// Jesli typ i warunek sa zgodne oznacza to ze ten zasob jest juz w trakcie pozyskiwanaia
						//isOnList = true;
					}
				}
			}
			
			if(!isOnList)
			{
				newRcToGain.add( missingRc.get(i) );
			}
		}
		
		return newRcToGain;
	}
	
	/**
	 * Zwraca liste zasobow (zaliczka) potrzebnych do podpisania kontraktu
	 * @param offer
	 * @param taskAgentName
	 * @return
	 */
	private List<Resource> getResourcesAdvance(Offer offer, String taskAgentName)
	{
		List<Resource> rcAdvance = new ArrayList<Resource>();
		List<ResourceValidation> rcvAdvance = offer.getResourcesIn(0);
		
		for(int i = 0; i<rcvAdvance.size(); i++)
		{
			for(int j =0; j<resourceList.size(); j++)
			{
				String rez = (String) resourceList.get(j).value1[0];
				String type = resourceList.get(j).value0.getType().getResourceTypeName();
				if(rez.compareTo(taskAgentName)==0 && type.compareTo(rcvAdvance.get(i).getType().getResourceTypeName())==0)
				{
					try {
						if(rcvAdvance.get(i).validateCondition(resourceList.get(j).value0))
						{
							Record<Resource, Object[]> rcd = resourceList.remove(j);
							rcd.value0.setOwner(new String(taskAgentName));
							rcAdvance.add(rcd.value0);
							j = 0;
							//break;
						}
					} catch (ParseExpressionErrorException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}
		
		return rcAdvance;
		
	}
	
	/**
	 * Przygotowuje parametry i uruchamia agenta zadania do pozyskania danego zasobu.
	 * @param index
	 *  Indeks z listy zasobow do pozyskania
	 * @param rcv
	 *  Obiekt klasy ResourceValidation, czyli zasob do pozyskania, zgodny z typem i spelniajacy warunki
	 */
	private void prepareAndStartTaskAgent(int index, ResourceValidation rcv)
	{	
		
		// Utworzenie unikatowej nazwy dla agenta zadania
		StringBuilder sb = new StringBuilder();
		sb.append(getLocalName());
		sb.append(rcv.getType().getResourceTypeName());
		//Date dt = new Date();
		//Long nb = dt.getTime();
		sb.append(generator.nextInt());
		String atName = sb.toString();			
		logger.debug("TaskAgent name to start: " + atName);
		
		// Dodanie agenta do sniffera
		if(Settings.isSniffer && Settings.sniffTask) {
			addAgentToSniffer(atName);
		}
		
		// Uruchomienie agenta zadania dla pozyskania tego zasobu
		if(startAgent( packageName + ".MbpTaskAgent", atName, new Object[]{ getLocalName(), rcv, new String(packageName)}))
		{
			// Wpisanie agenta zadania na liste
			taskAgents.put(new String(atName), new Record<TaskAgentState, Object>(TaskAgentState.WAIT, null));
			
			// Zapisanie nazwy agenta zadania dla tego zasobu do pozyskania
			validationList.get(index).value1[0] = new String(atName);
		}
	}
	
//	private void deleteAgents(int index)
//	{
//		List<String> toRemove = new ArrayList<String>();
//		for(int i = index-1; i>=0; i--)
//		{
//			toRemove.add(new String((String) validationList.get(i).value1[0]));		
//		}
//		
//		// Wyslanie zadania DODELETE do agentow zadan
//		for(int i = 0; i<toRemove.size(); i++)
//		{
//			contract cntr = (contract) taskAgents.get(toRemove.get(i)).value1;
//			sendReject(toRemove.get(i), cntr.uuid);
//		}
//	}
	
	/**
	 * Zrywa aktywny kontrakt
	 * @param index - Index listy RCV
	 */
	private void rejectContract(int index)
	{
		Record<ResourceValidation, Object[]> rcd = validationList.remove(index);
		String taskAgent = (String) rcd.value1[0];
		contract cntr = (contract) taskAgents.get(taskAgent).value1;
		String uuid = cntr.uuid;
		
		
		// Usuniecie rezerwacji dla usunietych agentow oraz zasobow virtualnych 
		// ktore mialy byc wynikiem realizacji dzialanie usunietych agentow zadan
		Iterator<Record<Resource, Object[]>> itRc = resourceList.iterator();
		while(itRc.hasNext())
		{
			Record<Resource, Object[]> rcdRc = itRc.next();
			String rez = (String) rcdRc.value1[0];
			String poz = (String) rcdRc.value1[2];
			if(rez.compareTo(taskAgent)==0)
			{
				rcdRc.value1[0] = "";
			}
			if(poz.compareTo(taskAgent)==0)
			{
				itRc.remove();
			}
		}
		
		// Wycofanie z magazynu zasobow ktore byly do dyspozycji agenta
		Message message = new Message(MessageType.RESOURCELGET, getLocalName(), Settings.storageName);
		extra ex = new extra();
		ex.name = "owner";
		ex.value = taskAgent;
		message.getContentXml().extras.add(ex);
		ACLMessage msg = message.GetACLMessage();	
		SenderLogger.send(this, msg);
		
		
		// Wyslanie REJECT do agenta zadania
		Message message2 = new Message(MessageType.REJECT, getLocalName(), taskAgent);
		extra ex2 = new extra();
		ex2.name = "uuid";
		ex2.value = uuid;
		message2.getContentXml().extras.add(ex2);
		ACLMessage msg2 = message2.GetACLMessage();	
		SenderLogger.send(this, msg2);
		
		taskAgents.get(taskAgent).value0 = TaskAgentState.WAIT;
		//contractList.get(uuid).state = "REJECTED";
	}
	
	private void deleteAgents(int index)
	{
		List<Integer> toRemove = new ArrayList<Integer>();
		int parentIndex = findIndexParent(index);
		while(parentIndex != -1)
		{
			toRemove.add(new Integer(parentIndex));
			parentIndex = findIndexParent(parentIndex);
		}
		
		for(int i = 0; i<toRemove.size(); i++)
		{
			rejectContract(toRemove.get(i));
		}
		
		//for(int i = index-1; i>=0; i--)
		//{
		//	rejectContract(i);
		//}
	}
	
	/**
	 * Znajduje index RCV agenta zaleznego
	 * @param index
	 * @return
	 */
	private int findIndexParent(int index)
	{
		int result = -1;
		if(validationList.size() == 0)
		{
			return result;
		}
		String agentParent = (String) validationList.get(index).value1[1];
		if(agentParent == "")
		{
			return result;
		}
		else
		{
			for(int i = 0; i<validationList.size(); i++)
			{
				String agent = (String) validationList.get(i).value1[0];
				if(agent.compareTo(agentParent)==0)
				{
					result = i;
					break;
				}
			}		
			return result;
		}
	}
	
	/**
	 * Usuwa obiekty Resource z listy zasobow ktorych ilosc dobra w zasobie jest rowna zero
	 */
	private void deleteEmptyResources()
	{
		Iterator<Record<Resource, Object[]>> it = resourceList.iterator();
		while(it.hasNext())
		{
			Record<Resource, Object[]> rcd = it.next();
			int quantity = rcd.value0.getQuantity();
			if(quantity==0)
			{
				it.remove();
			}
		}
	}
	
	/**
	 * Probuje scalic zasob o podanym indeksie z innym zasobem z listy
	 * @param index
	 */
	private void tryMergeResource(int index)
	{
		List<Resource> listTmp = new ArrayList<Resource>();
		Resource rc = resourceList.get(index).value0;
		// Wyznaczenie zasobow z ktorymi potencjalne mozna scalic odebrany zasob
		for(int i = 0; i<resourceList.size(); i++)
		{
			String rez = (String) resourceList.get(i).value1[0];
			long av = (Long) resourceList.get(i).value1[1];
			if(rez.compareTo("")==0 && av==0 && i!=index)
			{
				listTmp.add(resourceList.get(i).value0);
			}			
		}
		
		ResourceManager.tryToMerge(listTmp, rc);
	}
	
	/**
	 * Usuwa rezerwacje zasobow dla danego klienta i scala zasoby rzeczywiste ktorym zwolniona zostala rezerwacja
	 * @param agentName
	 */
	private void clearReservation(String agentName)
	{
		for(int i = 0; i<resourceList.size(); i++)
		{
			String rez = (String) resourceList.get(i).value1[0];
			long term = (Long) resourceList.get(i).value1[1];
			if(rez.compareTo(agentName)==0)
			{
				resourceList.get(i).value1[0] = "";
				if(term==0)
				{
					tryMergeResource(i);
				}
			}
		}		
		deleteEmptyResources();
	}
	
	private void clearAgent2()
	{
		// Nazwy agentow zadan do usuniecia
		List<String> toRemove = new ArrayList<String>();
				
		// Wyspecyfikownaie agentow do usuniecia
		Iterator<String> it = taskAgents.keySet().iterator();			
		while(it.hasNext())
		{
			String agentName = it.next();		
			toRemove.add(new String(agentName));		
		}
		
		// Wyslanie zadania DODELETE do agentow zadan
		for(int i = 0; i<toRemove.size(); i++)
		{
			Message message = new Message(MessageType.DODELETE, getLocalName(), toRemove.get(i));
			ACLMessage msgReply = message.GetACLMessage();
			SenderLogger.send(this, msgReply);
		}
		
		taskAgents.clear();
		validationList.clear();
		
		// Usuniecie zasobow wirtualnych
		Iterator<Record<Resource, Object[]>> itRc = resourceList.iterator();
		while(itRc.hasNext())
		{
			Record<Resource, Object[]> rcd = itRc.next();
			long term = (Long) rcd.value1[1];
			if(term>0)
			{
				itRc.remove();
			}
		}
		
		for(int i = 0; i<toRemove.size(); i++)
		{
			clearReservation(toRemove.get(i));
		}
	}
	
	/**
	 * Konczy prace wszystkich agentow zadan ktorzy nie realizuja kontraktow. Metoda wykorzystywana
	 * do przywracania agenta procesu biznesowego do stanu poczatkowego, ale tylko wtedy gdy zaden z 
	 * powolanych agentow zadan nie realizuje kontraktu. Do zkonczenia pracy agentow realizujacych
	 * kontrakty potrzebna jest inna metoda
	 */
	private void deleteTaskAgents()
	{
		// Nazwy agentow zadan do usuniecia
		List<String> toRemove = new ArrayList<String>();
		
		// Wyspecyfikownaie agentow do usuniecia
		Iterator<String> it = taskAgents.keySet().iterator();			
		while(it.hasNext())
		{
			String agentName = it.next();
			TaskAgentState taskAgentState = taskAgents.get(agentName).value0;
			if(taskAgentState == TaskAgentState.WAIT ||
					taskAgentState == TaskAgentState.NOSERVICE ||
					taskAgentState == TaskAgentState.NOOFFER ||
					taskAgentState == TaskAgentState.OFFER ||
					taskAgentState == TaskAgentState.READY)
			{	
				toRemove.add(new String(agentName));
			}			
		}
		
		
		// Wyslanie zadania DODELETE do agentow zadan
		for(int i = 0; i<toRemove.size(); i++)
		{
			Message message = new Message(MessageType.DODELETE, getLocalName(), toRemove.get(i));
			ACLMessage msgReply = message.GetACLMessage();
			SenderLogger.send(this, msgReply);
		}
		
		
		// Usuniecie elementow z listy ResourceValidation oznaczajacych zasoby do pozyskania
		// ktore mialy byc pozyskane przez usunietych agentow zadan
		for(int i = 0; i<toRemove.size(); i++)
		{
			Iterator<Record<ResourceValidation, Object[]>> itRcv = validationList.iterator();
			while(itRcv.hasNext())
			{
				Record<ResourceValidation, Object[]> rcd = itRcv.next();
				String poz = (String) rcd.value1[0];
				if(poz.compareTo(toRemove.get(i))==0)
				{
					itRcv.remove();
				}
			}
		}
		
		// Usuniecie agentow zadan z listy taskAgents
		for(int i = 0; i<toRemove.size(); i++)
		{
			taskAgents.remove(toRemove.get(i));
		}
		
		// Usuniecie rezerwacji dla usunietych agentow oraz zasobow virtualnych 
		// ktore mialy byc wynikiem realizacji dzialanie usunietych agentow zadan
		for(int i = 0; i<toRemove.size(); i++)
		{
			Iterator<Record<Resource, Object[]>> itRc = resourceList.iterator();
			while(itRc.hasNext())
			{
				Record<Resource, Object[]> rcd = itRc.next();
				//String rez = (String) rcd.value1[0];
				String poz = (String) rcd.value1[2];
				//if(rez.compareTo(toRemove.get(i))==0)
				//{
				//	rcd.value1[0] = "";
				//}
				if(poz.compareTo(toRemove.get(i))==0)
				{
					itRc.remove();
				}
			}
		}
		
		for(int i = 0; i<toRemove.size(); i++)
		{
			clearReservation(toRemove.get(i));
		}
	}
	
	/**
	 * Przywraca Agenta Procesu Biznesowego do stanu poczatkowego
	 */
	@Deprecated
	private void clearAgent()
	{
		// Wyslanie wiadomosci do wszystkich powolanych Agentow Zadan aby zakonczyili prace
		Iterator<String> it = taskAgents.keySet().iterator();			
		while(it.hasNext())
		{
			String agentName = it.next();
			
			Message message = new Message(MessageType.DODELETE, getLocalName(), agentName);
			ACLMessage msgReply = message.GetACLMessage();
			SenderLogger.send(this, msgReply);
			
			// Usuniecie z listy zasobow virtualnych
			Iterator<Record<Resource, Object[]>> it2 = resourceList.iterator();
			while(it2.hasNext())
			{
				Record<Resource, Object[]> rcd = it2.next();
				Long term = (Long) rcd.value1[1];
				String poz = (String) rcd.value1[2];
				if(term != 0)
				{
					if(poz.compareTo(agentName)==0)
					{
						it2.remove();
					}
				}
			}
		}
		
		// Wyczyszczenie listy agentow
		taskAgents.clear();
		
		// Wyczyszczenie listy zasobow do pozyskania
		for(int i = 0; i<validationList.size(); i++)
		{
			validationList.get(i).value1[0] = "";
		}
		
		validationList.clear();
		
		// Zwolnienie rezerwacji dla posiadanych zasobow.
		for(int i = 0; i<resourceList.size(); i++)
		{				
			resourceList.get(i).value1[0] = "";
		}		
	}
	
	
	//-------------------------------------------------------------------------------------//
	// Klasy wewnetrzne                                                                    //
	//-------------------------------------------------------------------------------------//
	
	/**
	 * Implementuje mechanizm kontoli procesu biznesowego. Wykonuje sie cyklicznie w osobnym watku.
	 * @author wojtek
	 *
	 */
	public class ClientAgentTicker extends TickerBehaviour
	{

		public ClientAgentTicker(Agent a, long period) {
			super(a, period);
			// TODO Auto-generated constructor stub
		}

		@Override
		protected void onTick() 
		{
			processing = true;
			//printRcInfo();
			printRcvInfo();
			boolean noservice = false; 
			
			// Sprawdzenie czy sa jakies zasoby do pozyskania
			if(validationList.size() == 0)
			{
				logger.info("No resources to gain.");
				//printRcInfo();
				return;
			}
			
			// Przetwarzanie listy zasobow do pozyskania, lista obiektow klasy ResourceValidation
			int index = 0;
			while(index < validationList.size())
			{
				// Pobranie referencji do obiektu ResourceValidation i nazwy agenta zadania zajmujacego sie sprawa
				ResourceValidation rcv = validationList.get(index).value0;
				String agentName = (String) validationList.get(index).value1[0];
				
				//logger.debug("Processing: RCV[" + index + "] [" + agentName + "] " + rcv.getType().getResourceTypeName());
				
				// Sprawdzenie czy dla tego zasobu dziala agent zadania, jesli nie agent jest uruchamiany
				if(agentName.compareTo("")==0)
				{
					ResourceValidation rcvCloned = mbp.message.Copier.cloneResourceValidation(rcv);
					prepareAndStartTaskAgent(index, rcvCloned);
					
					// Zakonczenie przetwarzania RCV[index]
					index = index + 1;
					continue;
				}
				
				// Sprawdzenie czy jest odpowiedz od agenta zadania w sprawie pozyskania tego zasobu
				TaskAgentState taskAgentState = taskAgents.get(agentName).value0;
				//logger.info("RCV[" + index + "] " + rcv.getType().getResourceTypeName() + 
				//		" [" + validationList.get(index).value1[0] + "] " + 
				//		" [" + validationList.get(index).value1[1] + "] " + taskAgentState );
				switch(taskAgentState)
				{
				// Brak odpowiedzi od agenta zadania
				case WAIT:
					logger.debug("No answer from task agent: " + agentName);
					break;
				// Agent zadania odpowiedzial: Brak uslugi
				case NOSERVICE:
					// Ustawienie zmiennej sterujacej brak uslugi. Oznacza to ze proces biznesowy
					// nie moze zostac ukonczony. Spowoduje to wyczyszczenie agenta
					noservice = true;
					
					// Wyslanie do agenta managera informacji aby wyswietlil komunikat o braku uslugi
					Message message = new Message(MessageType.EXTRA, getLocalName(), "manager");
					extra ex = new extra();
					ex.name = "message";
					ex.value = "Business process broken !!! \nRecieved NOSERVICE for resource: \n" + 
							rcv.getType().getResourceTypeName() + " " + rcv.getCondition() + "\n" +
							"Quantity: " + rcv.getQuantity().toString() + "\n" +
							"Realize term: " + rcv.integerValue.toString();
					message.getContentXml().extras.add(ex);
					ACLMessage msgReply = message.GetACLMessage();
					SenderLogger.send(this.myAgent, msgReply);
					
					break;
				case NOOFFER:
					noservice = true;
					
					// Wyslanie do agenta managera informacji aby wyswietlil komunikat o braku uslugi
					Message message2 = new Message(MessageType.EXTRA, getLocalName(), "manager");
					extra ex2 = new extra();
					ex2.name = "message";
					ex2.value = "Business process broken !!! \nRecieved NOOFFER for resource: \n" + 
							rcv.getType().getResourceTypeName() + " " + rcv.getCondition() + "\n" +
							"Quantity: " + rcv.getQuantity().toString() + "\n" +
							"Realize term: " + rcv.integerValue.toString();
					message2.getContentXml().extras.add(ex2);
					ACLMessage msgReply2 = message2.GetACLMessage();
					SenderLogger.send(this.myAgent, msgReply2);
					break;
				// Agent zadania wynegocjowal oferte
				case OFFER:
					// Pobranie referencji do oferty
					Offer offer = (Offer) taskAgents.get(agentName).value1;
					
					// Zwolnienie rezerwacji dla tego agenta jesli jakies byly. Sprawdzenie zasobow
					// i ewentualna rezerwacja zostanie wykonana ponownie
//					for(int i = 0; i<resourceList.size(); i++)
//					{
//						String rez = (String) resourceList.get(i).value1[0];
//						if(rez.compareTo(agentName)==0)
//						{
//							resourceList.get(i).value1[0] = "";
//							tryMergeResource(i);
//						}
//					}
//					
//					deleteEmptyResources();
					
					clearReservation(agentName);
					//printRcInfo();
					
					// Sprawdzenie posiadanych zasobow rezerwacja i wyznaczenie listy brakujacych
					List<ResourceValidation> missing = checkResources(offer, agentName);
					logger.info("Missing resources size: " + missing.size());
					//printRcInfo();
					if(missing.size()==0)
					{
						// Wszystkie potrzebne zasoby sa dostepne
						logger.info("No missing resources for: " + rcv.getType().getResourceTypeName() + " [" + index+  "]");
						
						// Dodanie do listy zasobow virtualnych zasobow bedacych wynikiem realizacji uslugi
						for(int i = 0; i<offer.getResourcesOut().size(); i++)
						{
							Resource virtRc = offer.getResourcesOut().get(i);
							// virtRc.setQuantity(quantity)
							// Termin realizacji, jednostki czasu
							int term = offer.getServiceRealizeTerm();
							resourceList.add(new Record<Resource, Object[]>(virtRc, new Object[]{"", new Long(term), new String(agentName)}));
						}
						
						// Oznaczenie gotowosci do podpisania kontraktu
						taskAgents.get(agentName).value0 = TaskAgentState.READY;
					}
					else
					{
						// Pobranie listy barkujacych zasobow ktorych nie ma na liscie do pozyskania
						List<ResourceValidation> newRcv = checkValidations(missing, agentName);
						
						// Dodanie brakujacych zasobow do listy zasobow do pozyskania przez agenta
						for(int i = 0; i<newRcv.size(); i++)
						{
							validationList.add(index+i+1, new Record<ResourceValidation, Object[]>(newRcv.get(i), new Object[]{"", new String(agentName)}));
							logger.info("Added new resource to gain at index: " + (index+i+1) + ", Type: " + newRcv.get(i).getType().getResourceTypeName());
						}
					}
					
					break;
				// Agent zadania odpowiedzial: Trwa realizacja kontraktu
				case REALIZE:
					//// Jeszcze nie zaimplementowane
					break;
				case READY:
					//// Tutaj nie sie nie robi
					break;
				case DONE:
					taskAgents.remove(agentName);
					validationList.remove(index);
					sendDoDelete(agentName);
					break;
				}//switch(taskAgentState)
				
				// Konczenie przetwarzania z uwagi na brak uslugi
				if(noservice)
					break;
				
				index = index + 1;
			}//while(index < validationList.size())
			
			// Ktorys z agentow zadan zglosil brak uslugi lub brak oferty
			if(noservice)
			{
				//resumeContracts();
				if(businessStarted)
				{
					deleteTaskAgents();
					deleteAgents(index);
				}
				else
				{
					deleteTaskAgents();
					//clearAgent2();
					//return;
				}
				//deleteTaskAgents();
				//deleteAgents(index);
				//resumeContracts();
				//return;
			}
			
			// Sprawdzenie warunkow do podpisania kontraktow
			boolean canSign = true;
//			for(int i = 0; i<validationList.size(); i++)
//			{
//				String agentName = (String) validationList.get(i).value1[0];
//				TaskAgentState taskAgentState = taskAgents.get(agentName).value0;
//				if(taskAgentState == TaskAgentState.WAIT ||
//						taskAgentState == TaskAgentState.NOSERVICE || 
//						taskAgentState == TaskAgentState.NOOFFER ||
//						taskAgentState == TaskAgentState.OFFER )
//				{
//					canSign = false;
//					break;
//				}
//			}
			
			Iterator<String> itTask = taskAgents.keySet().iterator();
			while(itTask.hasNext())
			{
				String agentName = itTask.next();
				TaskAgentState taskAgentState = taskAgents.get(agentName).value0;
				if(taskAgentState == TaskAgentState.WAIT ||
						taskAgentState == TaskAgentState.NOSERVICE || 
						taskAgentState == TaskAgentState.NOOFFER ||
						taskAgentState == TaskAgentState.OFFER )
				{
					canSign = false;
					break;
				}
			}
			
			
			// jezeli warunek podpisania kontraktow spelniony, chec podpisania kontraktow zostanie wyslana
			// do agentow ktorzy sa gotowi do podpisania kontraktow
			if(canSign)
			{
				//boolean signed = false;
				for(int i = validationList.size()-1; i>=0; i--)
				{
					String agentName = (String) validationList.get(i).value1[0];
					TaskAgentState taskAgentState = taskAgents.get(agentName).value0;
					if(taskAgentState == TaskAgentState.READY)
					{
						Offer offer = (Offer) taskAgents.get(agentName).value1;
						// Wyslanie zgody na podpisanie kontraktu
						taskAgents.get(agentName).value0 = TaskAgentState.WAIT;
						sendAcceptOffer(agentName, offer.GetUUID(), getResourcesAdvance(offer, agentName));
						
						businessStarted = true;
					}
				}
				
				//if(signed) {
					resumeContracts();
				//}
			}
			
		
			processing = false;
		}//onTick()
		
		
	}
	
	//-------------------------------------------------------------------------------------//
	// Metody do testow                                                                    //
	//-------------------------------------------------------------------------------------//
	
	public void printRcInfo()
	{
		StringBuilder sb = new StringBuilder();
		sb.append("Resource info:\n");
		for(int i = 0; i<resourceList.size(); i++)
		{
			sb.append("[" + resourceList.get(i).value1[0] + "] [" + resourceList.get(i).value1[1] + "] [" + resourceList.get(i).value1[2] + "] " +
					resourceList.get(i).value0.getType().getResourceTypeName() + "\n");
		}	
		logger.info(sb.toString());
	}
	
	public void printRcvInfo()
	{
		StringBuilder sb = new StringBuilder();
		sb.append("ResourceValidation info:\n");
		//int index = 0;
		for(int i = 0; i<validationList.size(); i++)
		{
			sb.append("RCV[" + i + "] " + validationList.get(i).value0.getType().getResourceTypeName() + " [" + validationList.get(i).value1[0] + "] [" + validationList.get(i).value1[1] + "]");
			String agentName = (String) validationList.get(i).value1[0];
			if(agentName.compareTo("")!=0)
			{
				TaskAgentState taskAgentState = taskAgents.get(agentName).value0;
				sb.append(" " + taskAgentState + "\n");
			}
			else
			{
				sb.append("\n");
			}
			
		}
		
		logger.info(sb.toString());
	}

}
